//////////////////////////////////////////////////////////////////////////
//
// GAM203
// Main Entry Point
// Main.cpp
// 
// Grant Johnson
// Qantm College
//
//////////////////////////////////////////////////////////////////////////

//Helpers
#include "DXMgr.h"
#include "InputMgr.h"
#include "RenderWindow.h"
#include "Renderer.h"
#include "ShaderMgr.h"
#include "World.h"
#include "SoundMgr.h"
#include <Time.h>
#include "MainSubject.h"
#include "TerrainManager.h"

//States
#include "StateManager.h"
#include "MainState.h"

//Forward Decared Functions
void InitSingletons();
void CleanSingletons();

//Entry point
int WINAPI WinMain(HINSTANCE a_hInst, HINSTANCE a_hPrevInst, LPSTR a_pCmdLine, int a_nCmdShow)
{
	//srand(time(NULL));
	//Initiate all singletons
	InitSingletons();

	StateManager& StateMgr = StateManager::GetInstance();

	//Create the window
	RenderWindow window;
	
	//Setup the window
	//if(!window.Setup("Immortal Engine - Level Editor", 1274, 768, a_hInst))
	//{
	//	MessageBox(NULL, "Failed to create the window!", "Fail!", MB_OK | MB_ICONEXCLAMATION);
	//	return 0;
	//}

	//Preload some sounds
	SoundMgr& SoundMgr = SoundMgr::GetInstance();
	SoundMgr.PreloadSample("media/Sound/jaguar.wav", true);
	SoundMgr.PreloadSample("media/Sound/Flame.wav", true);

	//Push the first state onto the stack
	StateMgr.PushState(&MainState::GetInstance());

	//Input manager acquire all
	InputMgr::GetInstance().AcquireAll();

	ShaderMgr::GetInstance().Load(DXMgr::GetInstance().GetDevice(), "BasicShader", "media/Shaders/BasicShader.fx");
	ShaderMgr::GetInstance().Load(DXMgr::GetInstance().GetDevice(), "BillboardShader", "media/Shaders/BillboardShader.fx");
	ShaderMgr::GetInstance().Load(DXMgr::GetInstance().GetDevice(), "AdvancedShader", "media/Shaders/AdvancedShader.fx");
	ShaderMgr::GetInstance().Load(DXMgr::GetInstance().GetDevice(), "MultiTextureShader", "media/Shaders/MultiTextureShader.fx");
	ShaderMgr::GetInstance().Load(DXMgr::GetInstance().GetDevice(), "ParticleShader", "media/Shaders/ParticleShader.fx");

	bool hasQuit = false;
	//Keep looping until program ends
	while(!hasQuit)
	{
		MSG msg;
		//Gets the next message, PM_REMOVE will remove it from the queue
		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			//Allows windows to perform processing on the message
			TranslateMessage(&msg);
			//Send the message to our window procedure
			DispatchMessage(&msg);

			if(msg.message == WM_QUIT)
			{
				//If it has received a quit message, then exit the loop
				hasQuit = true;
			}
		}
		//Get delta time
		float dt = window.GetDeltaTime();

		//Update the render window
		window.Update();

		MainSubject::GetInstance().Update();

		//Update input
		InputMgr::GetInstance().Update();

		//Call update on the current state
		StateMgr.GetCurrentState()->Update(dt);
		
		//Call render on the current state
		StateMgr.GetCurrentState()->Render(dt);

		D3DXVECTOR3 cameraPos = Renderer::GetInstance().GetActiveCamera().GetEyePos();
		D3DXVECTOR3 cameraDir = Renderer::GetInstance().GetActiveCamera().GetLookVec() - Renderer::GetInstance().GetActiveCamera().GetEyePos();
		SoundMgr::GetInstance().SetListener(cameraPos.x, cameraPos.y, cameraPos.z, cameraDir.x, cameraDir.y, cameraDir.z);
		SoundMgr::GetInstance().Update();

		if(InputMgr::GetInstance().IsKeyPressed(DIK_ESCAPE))
		{
			PostQuitMessage(0);
			return 0;
		}
	}
	//Clean up all singletons
	CleanSingletons();

	return 0;
}

void InitSingletons()
{
	MainSubject::Init();
	World::Init();
	Renderer::Init();
	//Init States
	StateManager::Init();
	MainState::Init();
	TerrainManager::Init();
	//Init Singletons
	ShaderMgr::Init();
	InputMgr::Init();
	SoundMgr::Init();
	DXMgr::Init();
}

void CleanSingletons()
{
	MainSubject::Done();
	//Cleanup states
	StateManager::Done();
	MainState::Done();
	World::Done();
	Renderer::Done();
	TerrainManager::Done();
	//Clean up singletons
	ShaderMgr::Done();
	InputMgr::Done();
	SoundMgr::Done();
	DXMgr::Done();
}